package lottery.impl;

import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.Random;

import javax.ejb.Schedule;
import javax.ejb.Singleton;
import javax.persistence.EntityManager;
import javax.persistence.NoResultException;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;

import lottery.impl.entities.Bet;
import lottery.impl.entities.Lottery;

@Singleton
public class LotteryGeneratorService {
	
	@PersistenceContext(unitName="lottery")
	EntityManager em;
	
	private int previousMinute = 0;

	@Schedule(minute="*/3", hour="*", persistent=false)
	public void lotteryGenerator() throws Exception {
	
		Calendar rightNow = Calendar.getInstance();
		int currentMinute = rightNow.get(Calendar.MINUTE);

		if((previousMinute + 3) <= currentMinute || previousMinute > currentMinute ){ // https://issues.jboss.org/browse/EJBTHREE-2229

			// Random generator definition
		    Random randomGenerator = new Random();
			
		    //
		    boolean noOnGoingLottery = false;
		    
			// Retrieve the on going lottery
			Query query = em.createNamedQuery("lottery.onGoing");
			
			Lottery closingLottery = null;
			
			try{
				closingLottery = (Lottery) query.getSingleResult();
			}catch(NoResultException e){
				noOnGoingLottery = true;
			}
			
			if(!noOnGoingLottery){
				// Close the on going lottery
				closingLottery.setOnGoing(false);
				try {
					em.persist(closingLottery);
				} catch (Exception e) {
					throw new Exception("Error updating on going lottery.", e);
				}
			}
			
			// Generate a new lottery
			Lottery newLottery = new Lottery();
			
			newLottery.setOnGoing(true);
			newLottery.setLotteryDescription("Lottery [" + System.currentTimeMillis() + "]");
			newLottery.setTimestamp(new Date(System.currentTimeMillis()));
			newLottery.setTotalAmount(0.0);
			newLottery.setWinMultiplier(randomGenerator.nextInt(10) + 1);
				
			// Update the database with the new lottery
			try {
				em.persist(newLottery);	
			} catch (Exception e) {
				throw new Exception("Error creating the first lottery.", e);
			}
	
			if(!noOnGoingLottery){
				// Generate the result for the closing lottery
				closingLottery.setResult(randomGenerator.nextInt(101));
				
				try {
					em.persist(closingLottery);
				} catch (Exception e) {
					throw new Exception("Error updating lottery result.", e);
				}
				
				// Retrieve winning bets
				Query winnersQuery = em.createNamedQuery("bet.winners");
				winnersQuery.setParameter("lottResult", closingLottery.getResult().intValue());
				
				@SuppressWarnings("unchecked")
				List<Bet> winnersList = winnersQuery.getResultList();
				
				// Update the winning bets
				for(Bet winningBet : winnersList){
					// Update the amount due according to the bet and the existing multiplier
					winningBet.setAmountDue( closingLottery.getWinMultiplier() * winningBet.getAmountBetted() );
					
					try {
						em.persist(winningBet);
					} catch (Exception e) {
						throw new Exception("Error updating winning bets.", e);
					}				
				}
			}
			
			previousMinute = currentMinute;
		}
	}
	
}
